package com.jiangli.utils;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class HashObjectConverter {

    /**
     * 将Redis Hash转换为Java对象
     * @param redisTemplate Redis模板
     * @param hashKey Redis Hash的外层Key
     * @param clazz 目标对象的类
     * @param <T> 目标对象类型
     * @return 转换后的Java对象（null表示Hash不存在）
     */
    public static <T> T hashToObject(StringRedisTemplate redisTemplate,
                                     String hashKey,
                                     Class<T> clazz) {
        String emptyKey = hashKey+":empty";
        Boolean isEmpty = redisTemplate.hasKey (emptyKey);
        if (Boolean.TRUE.equals (isEmpty)) {
            return null; // 空标识存在 → 返回 null
        }
        // 1. 从Redis读取Hash的所有键值对
        Map<Object, Object> hashMap = redisTemplate.opsForHash().entries(hashKey);
        if (hashMap.isEmpty()) {
            return null;
        }

        try {
            // 2. 创建对象实例
            T obj = clazz.getDeclaredConstructor().newInstance();

            // 3. 反射获取所有字段，映射Hash的field到对象属性
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 允许访问私有字段
                field.setAccessible(true);

                // Hash的field名称与对象属性名一致（如"name"对应name属性）
                String fieldName = field.getName();
                Object value = hashMap.get(fieldName);

                if (value != null) {
                    // 根据字段类型转换值（这里处理常见类型，可扩展）
                    Object convertedValue = convertValue(value.toString(), field.getType());
                    field.set(obj, convertedValue);
                }
            }

            return obj;
        } catch (Exception e) {
            throw new RuntimeException("Hash转换为对象失败", e);
        }
    }

    /**
     * 将Java对象转换为Redis Hash并存储
     * @param redisTemplate Redis模板
     * @param hashKey Redis Hash的外层Key
     * @param obj 要转换的Java对象
     * @param expireSeconds 过期时间（秒）
     */
    public static void objectToHash(StringRedisTemplate redisTemplate,
                                    String hashKey,
                                    Object obj,
                                    long expireSeconds) {
        try {
            // 1. 创建Hash的field-value映射（属性名→属性值字符串）
            Map<String, String> hashMap = new HashMap<>();

            // 2. 反射获取对象所有字段
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(obj);

                if (value != null) {
                    hashMap.put(fieldName, value.toString());
                }
            }

            // 3. 存入Redis Hash
            redisTemplate.opsForHash().putAll(hashKey, hashMap);
            // 设置过期时间
            redisTemplate.expire(hashKey, expireSeconds, java.util.concurrent.TimeUnit.SECONDS);

        } catch (Exception e) {
            throw new RuntimeException("对象转换为Hash失败", e);
        }
    }

    /**
     * 类型转换：将字符串转换为目标类型
     */
    private static Object convertValue(String value, Class<?> targetType) {
        if (targetType == String.class) {
            return value;
        } else if (targetType == Long.class || targetType == long.class) {
            return Long.valueOf(value);
        } else if (targetType == Integer.class || targetType == int.class) {
            return Integer.valueOf(value);
        } else if (targetType == Double.class || targetType == double.class) {
            return Double.valueOf(value);
        } else if (targetType == Boolean.class || targetType == boolean.class) {
            return Boolean.valueOf(value);
        }
        // 可扩展其他类型（如LocalDateTime）
        throw new IllegalArgumentException("不支持的类型转换：" + targetType);
    }
}